<script lang="ts" setup>
// #region 引入包, 函数和组件
import { computed, nextTick, ref, watch } from 'vue'
import { useUserStore } from '@/stores/userStore'
import type { MessageListItem, MessageUserList } from '@/interfaces/ChatType'
import { ElMessage } from 'element-plus'
// #endregion

// #region // 使用模块(仓库、路由、父组件参数函数)
const store = useUserStore()
// #endregion

// #region // 变量
let socket: WebSocket
const userList = ref<MessageUserList[]>([]) // 用户列表
const curId = ref(0) // 当前聊天对象的id
const sayText = ref('') // 说话的文本
const messageList = ref<MessageListItem[]>([]) // 当前聊天对象对应的消息列表
const chatRef = ref<HTMLDivElement | null>(null) // 聊天盒子实例
// 当前聊天对象
const curUserChat = computed(() => {
  if (!curId.value) return null
  return userList.value.find((v) => v.userid === curId.value)
})
// #endregion

// #region // 函数
// 表单提交事件
const submitHandle = (e: Event) => {
  e.preventDefault()
  console.log(sayText.value)

  if (sayText.value.trim().length === 0) {
    ElMessage({
      type: 'warning',
      message: '请输入要说的话',
    })
    return
  }
  if (!store.user) return ElMessage.error('用户信息加载失败')
  socket.send(
    JSON.stringify({
      type: 0x05,
      data: {
        userid: store.user?.userId,
        targetid: curId.value,
        msgTime: Date.now(),
        msgType: 0x01,
        message: sayText.value,
      },
    }),
  )
  sayText.value = ''
}
// 点击关闭聊天窗口
const closeChatPop = () => {
  curId.value = 0
  sayText.value = ''
}
// 点击后切换聊天对象
const changeCurId = (id: number) => {
  curId.value = id
}
// 打开连接处理函数
const openHandler = () => {
  console.log('连接已打开')
  // user还没有返回
  if (!store.user) return
  socket.send(
    JSON.stringify({
      type: 0x01,
      data: { userid: store.user.userId, uname: store.user.uname, avatar: store.user.avatar },
    }),
  )
}
// 消息处理函数
const messageHandler = (event: MessageEvent<string>) => {
  // console.log('收到消息:', event.data)
  // 用户列表
  const res = JSON.parse(event.data)
  console.log(res)
  switch (res.type) {
    case 2:
      userList.value = res.data as MessageUserList[]
      break
    case 4:
      if (res.data.length === 0 || res.data[res.data.length - 1].userid === curId.value || store.user?.userId === res.data[res.data.length - 1].userid)
      messageList.value = res.data as MessageListItem[]
      break
    case 6:
      ElMessage.error(res.data.message)
  }
}

// 关闭连接处理函数
const closeHandler = () => {
  console.log('连接已关闭')
}
// 错误处理函数
const errorHandler = (error: Event) => {
  console.error('连接错误:', error)
}
// 心跳函数
const heartbeat = () => {
  socket.send(
    JSON.stringify({
      type: 0x07,
      data: {
        userid: store.user?.userId,
      },
    }),
  )
}
// 初始化函数
const init = () => {
  socket = new WebSocket('ws://localhost:4600')
  socket.addEventListener('open', openHandler)
  socket.addEventListener('message', messageHandler)
  socket.addEventListener('close', closeHandler)
  socket.addEventListener('error', errorHandler)
  setInterval(heartbeat, 1000)
}
// #endregion

// #region // 生命周期和vue函数
init() // 初始化
watch(curId, () => {
  if (!curId.value) return
  socket.send(
    JSON.stringify({
      type: 0x03,
      data: {
        userid: store.user?.userId,
        targetid: curId.value,
      },
    }),
  )
})
watch(messageList, async () => {
  await nextTick()
  if (!curId.value) return
  if (!messageList.value.length) return
  if (!chatRef.value) return
  // console.log(chatRef.value)
  // console.log(chatRef.value.scrollTop, chatRef.value.scrollHeight)
  if (chatRef.value.scrollHeight - chatRef.value.scrollTop - chatRef.value.clientHeight < 100)
    chatRef.value.scrollTop = chatRef.value.scrollHeight
})
// #endregion
</script>

<template>
  <div class="chat_container">
    <div class="user_list">
      <el-text class="user_title">用户列表</el-text>
      <div
        v-for="item in userList"
        :key="item.userid"
        :class="['user', { active: curId === item.userid }]"
        @click="changeCurId(item.userid)"
      >
        <el-avatar :size="25" :src="item.avatar"></el-avatar>
        <el-text>{{ item.uname }}</el-text>
      </div>
    </div>
    <div class="chat_pop" v-if="curUserChat">
      <div class="chat_head">
        {{ curUserChat.uname }}
        <el-text @click="closeChatPop">关闭</el-text>
      </div>
      <div class="chat_wrap" ref="chatRef">
        <div class="chat_msg" v-for="(item, index) in messageList" :key="item.userid + Math.random()">
          <span v-if="index === 0 || item.msgTime - messageList[index - 1].msgTime > 360000">{{
            new Date(item.msgTime)
              .toLocaleString('zh-cn', {
                year: '2-digit',
                month: '2-digit',
                day: '2-digit',
                weekday: 'long',
                hour: '2-digit',
                minute: '2-digit',
              })
              .slice(3)
          }}</span>
          <div :class="item.userid === store.user?.userId ? 'right' : 'left'">
            <el-avatar shape="square" :size="25" :src="item.userAvatar"></el-avatar>
            <span class="msg_text">{{ item.message }}</span>
          </div>
        </div>
      </div>
      <div class="chat_inline">
        <el-form @submit="submitHandle">
          <el-form-item>
            <el-avatar :size="25" :src="store.user?.avatar"></el-avatar>
            <el-text>{{ store.user?.uname }}说：</el-text>
          </el-form-item>
          <el-form-item class="input_text">
            <el-input
              v-model="sayText"
              style="width: 100%"
              :rows="4"
              type="textarea"
              placeholder="请输入您要说的话~"
              resize="none"
              :autofocus="true"
            />
            <el-button native-type="submit" plain type="primary">发送</el-button>
          </el-form-item>
        </el-form>
      </div>
    </div>
    <div class="empty" v-else>请选择聊天对象...</div>
  </div>
</template>

<style lang="sass" scoped>
.chat_container
  display: flex
  border-top: 1px solid #eee
  border-left: 1px solid #eee

  .user_list
    min-width: 200px
    max-width: 300px
    height: 100%
    background: #fff
    box-shadow: 1px 0 5px rgba(0, 0, 0, 0.1)
    overflow: hidden
    overflow-y: auto
    padding: 0 5px
    .user_title
      font-size: 16px
      text-align: center
      display: block
      padding: 10px
      border-bottom: 1px solid #f6f6f6
      font-weight: 560
      margin-bottom: 10px
    .user
      padding: 10px 20px
      display: flex
      align-items: center
      border-bottom: 1px solid #f4f4f4
      border-radius: 8px
      .el-text
        font-size: 16px
        margin-left: 10px
    .active
      background: #f4f4f4

  .chat_pop
    flex: 1
    background: #f8f8f8
    display: flex
    flex-direction: column
    min-width: 600px
    .chat_head
      font-size: 16px
      text-align: center
      padding: 10px
      border-bottom: 1px solid #f6f6f6
      background: #fff
      position: relative
      .el-text
        position: absolute
        right: 10px
        top: 50%
        transform: translateY(-50%)
        cursor: pointer
        user-select: none
        &:hover
          color: #f00
    .chat_wrap
      flex: 1
      box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.2)
      overflow: hidden
      overflow-y: auto
      &::-webkit-scrollbar
        display: none
      .chat_msg > span
        display: block
        text-align: center
        line-height: 50px
        color: #999
        font-size: 14px
      .left, .right
        display: flex
        align-items: center
        padding: 10px 20px
        .msg_text
          padding: 2px 10px
          border-radius: 3px
          background: #fff
          box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3 )
      .left
        justify-content: start
        .el-avatar
          margin-right: 10px
      .right
        justify-content: end
        flex-direction: row-reverse
        .el-avatar
          margin-left: 10px

    .chat_inline
      height: 160px
      background: #fff
      border-left: 1px solid #eee
      padding: 20px
      padding-top: 0
      .el-form
        width: 100%
        height: 100%
        display: flex
        flex-direction: column
        .el-form-item
          flex: 1
          margin: 0
        .el-avatar
          margin: 10px
        .input_text
          position: relative
          :deep(.el-textarea__inner)
            padding-right: 100px
          .el-button
            position: absolute
            bottom: 0
            right: 0

  .empty
    display: flex
    align-items: center
    justify-content: center
    flex: 1
    font-size: 20px
    color: #999
</style>
